观察者模式(Observer Pattern)
在对象之间建立一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象都会收到通知,并自动更新。
设计原则
- 找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起
- 针对接口编程,而不是针对实现编程
- 多用组合,少用继承
- 为了交互对象之间的松耦合设计而努力
气象观测站
有一个气象观测站,可以获取到温度、湿度、气压等数据。每隔一定时间都会更新数据。
有三个布告板,根据不同的规则显示气象数据。(当前温度湿度布告板、气温统计布告板、气压变化布告板)
当气象观测站更新测量数据后,需要通知三个布告板,更新布告板上的数据。


问题所在:
- 针对具体实现编程,而非接口
- 对于每个新的布告板,都需要修改代码
- 无法在运行时动态地增加或删除布告板
- 尚未封装改变的部分
利用松耦合原则重新设计

定义接口:
1 | public interface Observer { |
1 | public interface Subject { |
1 | public interface DisplayElement { |
定义气象站:
1 | public class WeatherData implements Subject { |
定义布告板:
1 | public class CurrentConditionsDisplay implements Observer, DisplayElement { |
1 | public class StatisticsDisplay implements Observer, DisplayElement { |
1 | public class ForecastDisplay implements Observer, DisplayElement { |
测试代码:
1 | public class Main { |
运行结果:
1 | CurrentConditionsDisplay temperature:80.0 humidity:65.0 |
上述实现中,每次数据更新后,都会主动推送数据到布告板。
其实有的布告板不需要那么多的数据,当然布告板可以通过拉取的方式获取自己想要的数据。
使用 JAVA 内置的观察者模式
java 内置了 Observer 接口和 Observable 类来实现观察者模式。

定义气象站:
1 | public class WeatherData extends Observable { |
定义布告板:
1 | public class CurrentConditionsDisplay implements Observer, DisplayElement { |
1 | public class StatisticsDisplay implements Observer, DisplayElement { |
1 | public class ForecastDisplay implements Observer, DisplayElement { |
测试代码:
1 | public class Main { |
运行结果:
1 | Forecast: Improving weather on the way! |
这里使用 notifyObservers() 方法,通知布告板,布告板收到通知后主动拉取数据。
也可以改为 notifyObservers(Object arg) 方法,主动推送数据。
Observalbe 类中,setChanged() 方法用于标志是否需要发送通知。(假如气象站每秒更新一次数据,而布告板只需要每小时更新一次数据,此时,可以通过 setChanged() 方法来灵活地控制通知时间)
总结
为了交互对象之间的松耦合设计而努力。
在对象之间建立一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象都会收到通知,并自动更新。